<?php

namespace App\Services\SuperAdmin;

use App\Exceptions\SuperAdminException;
use App\Helpers\MvcHelper;
use Exception;
use Illuminate\Support\Facades\DB;

class MenuService extends BaseSuperAdminService
{
    /**
     * 菜单树
     *
     * @return array
     * @throws Exception
     */
    public function getMenu(): array
    {
        // 获取菜单ids
        $menusIds = $this->getAuthorityMenusModel()->getMenusIdsByAuthorityId(MvcHelper::getUserInfoCache()['authority_id']);

        // 获取菜单列表
        $menusList = $this->getMenusModel()->getItemsByIds($menusIds, [
            'id', 'parent_id', 'path', 'name', 'hidden', 'component', 'sort', 'active_name', 'keep_alive', 'default_menu', 'title', 'icon', 'close_tab',
        ]);

        $allMenus = $this->_handleMenuList($menusList);

        return [
            'list' => $this->_handleMenuTree($allMenus),
        ];
    }

    /**
     * 获取用户动态路由
     *
     * @return array
     * @throws Exception
     */
    public function getMenuTree(): array
    {
        // 获取菜单列表
        $menusList = $this->getMenusModel()->getList([
            'id', 'parent_id', 'path', 'name', 'hidden', 'component', 'sort', 'active_name', 'keep_alive', 'default_menu', 'title', 'icon', 'close_tab',
        ]);

        $allMenus = $this->_handleMenuList($menusList);

        return [
            'list' => $this->_handleMenuTree($allMenus),
        ];
    }

    /**
     * 菜单列表
     *
     * @return array
     * @throws Exception
     */
    public function getMenuList(): array
    {
        // 获取菜单列表
        $menusList = $this->getMenusModel()->getList([
            'id', 'parent_id', 'path', 'name', 'hidden', 'component', 'sort', 'active_name', 'keep_alive', 'default_menu', 'title', 'icon', 'close_tab',
        ]);

        $allMenus = $this->_handleMenuList($menusList);

        return [
            'list' => $this->_handleMenuTree($allMenus),
        ];
    }

    /**
     * 根据id获取菜单
     *
     * @param array $params
     * @return array
     * @throws Exception
     */
    public function getMenuById(array $params): array
    {
        // 获取菜单
        $menuInfo = $this->getMenusModel()->getItemById($params['id'], [
            'id', 'parent_id', 'path', 'name', 'hidden', 'component', 'sort', 'active_name', 'keep_alive', 'default_menu', 'title', 'icon', 'close_tab',
        ]);
        return $this->_handleMenu($menuInfo);
    }

    /**
     * 根据
     *
     * @param array $params
     * @return array
     * @throws Exception
     */
    public function getMenusByAuthorityId(array $params): array
    {
        // 获取authorityMenuList
        $menuAuthorityList = $this->getAuthorityMenusModel()->getItemsByAuthorityId($params['authorityId'], [
            'id', 'menu_id',
        ]);

        $menuIds = array_column($menuAuthorityList, 'menu_id');

        // 获取menus
        $menuList = $this->getMenusModel()->getItemsByIds($menuIds, [
            'id', 'parent_id', 'name',
        ]);

        $menuListMap = array_column($menuList, null, 'id');

        $list = [];
        foreach ($menuAuthorityList as $item) {
            $list[] = [
                'id'       => $item['id'],
                'menuId'   => $item['menu_id'],
                'parentId' => $menuListMap[$item['menu_id']]['parent_id'] ?? 0,
                'name'     => $menuListMap[$item['menu_id']]['name'] ?? '',
            ];
        }

        return [
            'list' => $list,
        ];
    }

    /**
     * 更新菜单
     *
     * @return void
     * @throws Exception
     */
    public function updateMenu(array $params)
    {
        // 查询菜单
        $menuInfo = $this->getMenusModel()->getItemById($params['id'], [
            'id', 'parent_id', 'path', 'name', 'component', 'sort', 'active_name', 'keep_alive', 'default_menu', 'title', 'icon', 'close_tab',
        ]);
        if (empty($menuInfo)) {
            throw new SuperAdminException('登录状态失效，请重新登录', SuperAdminException::CODE_1001);
        }

        // 查询是否存在相同name的菜单
        $otherMenuInfo = $this->getMenusModel()->getMenuByName($params['id'], $params['name']);
        if ($otherMenuInfo) {
            throw new SuperAdminException('存在相同name修改失败', SuperAdminException::CODE_1002);
        }

        // 更新菜单
        $updateData = $this->_handleUpdateMenuData($params);

        DB::transaction(function () use ($params, $updateData) {
//            // 新增菜单按钮
            $this->getMenusModel()->updateItemById($params['id'], $updateData);
        });
    }

    /**
     * 添加菜单
     *
     * @return void
     * @throws Exception
     */
    public function addMenu(array $params)
    {
        $menu = $this->getMenusModel()->getMenuByName(0, $params['name']);
        if ($menu) {
            throw new SuperAdminException('存在相同name修改失败', SuperAdminException::CODE_1002);
        }

        $addItem = $this->_handleAddMenuData($params);

        // 添加菜单
        $this->getMenusModel()->addItem($addItem);
    }

    /**
     * 删除菜单
     *
     * @param array $params
     * @return void
     * @throws SuperAdminException
     */
    public function deleteMenu(array $params): void
    {
        $menu = $this->getMenusModel()->getItemById($params['id'], [
            'id', 'name',
        ]);
        if (empty($menu)) {
            throw new SuperAdminException('菜单不存在', SuperAdminException::CODE_1002);
        }

        // 查询是否存在子菜单
        $subMenu = $this->getMenusModel()->getItemByParentId($params['id']);
        if ($subMenu) {
            throw new SuperAdminException('此菜单存在子菜单不可删除', SuperAdminException::CODE_1004);
        }

        // 查询菜单是否有角色作为首页
        $authority = $this->getAuthoritiesModel()->getItemByDefaultRouter($menu['name']);
        if ($authority) {
            throw new SuperAdminException('此菜单有角色正在作为首页，不可删除', SuperAdminException::CODE_1005);
        }

        // 删除菜单
        DB::transaction(function () use ($params) {
            // 删除菜单
            $this->getMenusModel()->deleteItemById($params['id']);
            // 删除角色关联的菜单
            $this->getAuthorityMenusModel()->deleteItemByMenuId($params['id']);
        });
    }

    /**
     * 添加角色菜单
     *
     * @return void
     * @throws Exception
     */
    public function addMenuAuthority(array $params)
    {
        $menuIds = array_column($params['menus'], 'id');
        // 查询是否存在
        $oldMenuIds = $this->getAuthorityMenusModel()->getMenusIdsByAuthorityId($params['authorityId']);

        // 需要新增的菜单
        $addMenuIds = array_diff($menuIds, $oldMenuIds);

        // 需要删除的菜单
        $deleteMenuIds = array_diff($oldMenuIds, $menuIds);
        if (empty($addMenuIds) && empty($deleteMenuIds)) {
            return;
        }
        $addMenuList = [];
        if (!empty($addMenuIds)) {
            foreach ($addMenuIds as $menuId) {
                $addMenuList[] = [
                    'menu_id'      => $menuId,
                    'authority_id' => $params['authorityId'],
                ];
            }
        }

        // 更新数据
        DB::transaction(function () use ($params, $addMenuList, $deleteMenuIds) {
            // 添加角色菜单
            $addMenuList && $this->getAuthorityMenusModel()->addItem($addMenuList);
            // 删除角色菜单
            $deleteMenuIds && $this->getAuthorityMenusModel()->deleteItemByAuthorityIdAndMenuIds($params['authorityId'], $deleteMenuIds);
        });
    }

    private function _handleUpdateMenuData(array $params): array
    {
        $updateData = [];
        !empty($params['meta']['keepAlive']) && $updateData['keep_alive'] = $params['meta']['keep_alive'];
        !empty($params['meta']['closeTab']) && $updateData['close_tab'] = $params['meta']['closeTab'];
        !empty($params['meta']['defaultMenu']) && $updateData['default_menu'] = $params['meta']['defaultMenu'];
        !empty($params['meta']['icon']) && $updateData['icon'] = $params['meta']['icon'];
        !empty($params['meta']['title']) && $updateData['title'] = $params['meta']['title'];

        !empty($params['component']) && $updateData['component'] = $params['component'];
        !empty($params['name']) && $updateData['name'] = $params['name'];
        !empty($params['parentId']) && $updateData['parent_id'] = $params['parentId'];
        !empty($params['path']) && $updateData['path'] = $params['path'];
        !empty($params['sort']) && $updateData['sort'] = $params['sort'];

        if (isset($params['hidden'])) {
            $updateData['hidden'] = intval($params['hidden']);
        }

        return $updateData;
    }

    private function _handleAddMenuData($params): array
    {
        return [
            'keep_alive'   => $params['meta']['keepAlive'],
            'close_tab'    => $params['meta']['closeTab'],
            'default_menu' => $params['meta']['defaultMenu'],
            'icon'         => $params['meta']['icon'],
            'title'        => $params['meta']['title'],
            'component'    => $params['component'],
            'name'         => $params['name'],
            'parent_id'    => $params['parentId'],
            'path'         => $params['path'],
            'sort'         => $params['sort'] ?? 0,
            'hidden'       => $params['hidden'],
        ];
    }

    /**
     * @throws Exception
     */
    private function _handleMenuList(array $menusList): array
    {
//        $menusIds = array_column($menusList, 'id');
//        // 查询菜单范围
//        $menuParameters    = $this->getMenuParametersModel()->getItemsByMenuIds($menusIds, [
//            'id', 'menu_id', 'type', 'key', 'value',
//        ]);
//        $menuParametersMap = array_column($menuParameters, null, 'menu_id');

        $allMenus = [];
        foreach ($menusList as $item) {
            $allMenus[] = $this->_handleMenu($item);
        }
        return $allMenus;
    }

    public function _handleMenu($item): array
    {
        return [
            'id'          => $item['id'],
            'parentId'    => $item['parent_id'],
            'path'        => $item['path'],
            'name'        => $item['name'],
            'hidden'      => boolval($item['hidden']),
            'component'   => $item['component'],
            'sort'        => $item['sort'],
            'meta'        => [
                'activeName'  => $item['active_name'],
                'keepAlive'   => $item['keep_alive'],
                'defaultMenu' => $item['default_menu'],
                'title'       => $item['title'],
                'icon'        => $item['icon'],
                'closeTab'    => $item['close_tab'],
            ],
            'authorityId' => MvcHelper::getUserInfoCache()['authority_id'],
            'menuId'      => $item['id'],
            'parameters'  => $menuParametersMap[$item['id']] ?? [],
        ];
    }

    private function _handleMenuTree($allMenus)
    {
        $menuTree = [];
        foreach ($allMenus as $item) {
            $menuTree[$item['parentId']][] = $item;
        }

        $menus = $menuTree[0];


        for ($i = 0; $i < count($menus); $i++) {
            $this->_getChildrenList($menus[$i], $menuTree);
        }

        return $menus;
    }

    private function _getChildrenList(&$menu, $menuTree): void
    {
        $menu['children'] = $menuTree[$menu['id']] ?? [];
        for ($i = 0; $i < count($menu['children']); $i++) {
            $this->_getChildrenList($menu['children'][$i], $menuTree);
        }
    }
}
